﻿using Microsoft.Extensions.Configuration;

namespace MiniFox.Configurations
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class ConfigurationFactory : IConfigurationFactory
    {

        #region static members 
        static bool _initialized;
        static ConfigurationFactory _instance;
        static ConfigurationFactory()
        {
            _initialized = false;
        }
        /// <summary>
        /// 
        /// </summary>
        public static ConfigurationFactory Instance
        {
            get
            {
                return _instance;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public static void Initialize(string envName = null)
        {
            IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddJsonFile(string.IsNullOrEmpty(envName) ? "appsettings.json":$"appsettings.{envName}.json");
            IConfiguration configuration = configurationBuilder.Build();
            Initialize(configuration);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="configuration"></param>
        public static void Initialize(IConfiguration configuration)
        {
            if (_initialized)
                return;

            _instance = new JsonConfigurationFactory(configuration);
            _initialized = true;
        }
        /// <summary>
        /// 
        /// </summary>
        public static Dictionary<string, string> CommonSettings
        {
            get
            {
                return Instance.Settings;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetConfig<T>() where T: class
        {
            return Instance.GetConfiguration<T>();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sectionName"></param>
        /// <returns></returns>
        public static T GetConfig<T>(string sectionName) where T : class
        {
            return Instance.GetConfiguration<T>(sectionName);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="configType"></param>
        /// <returns></returns>
        public static object GetConfig(Type configType)
        {
            return Instance.GetConfiguration(configType);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="configType"></param>
        /// <param name="sectionName"></param>
        /// <returns></returns>
        public static object GetConfig(Type configType, string sectionName)
        {
            return Instance.GetConfiguration(configType, sectionName);
        }
        #endregion

        #region config section
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetConfiguration<T>() where T : class
        {
            return GetConfiguration<T>(null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sectionName"></param>
        /// <returns></returns>
        public T GetConfiguration<T>(string sectionName) where T : class
        {
            Type type = typeof(T);
            T configSection = GetConfiguration(type, sectionName) as T;
            return configSection;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="configType"></param>
        /// <returns></returns>
        protected internal object GetConfiguration(Type configType)
        {
            return GetConfiguration(configType, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="configType"></param>
        /// <param name="sectionName"></param>
        /// <returns></returns>
        protected internal abstract object GetConfiguration(Type configType, string sectionName);
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public abstract Dictionary<string, string> Settings 
        {
            get;
        }
        #endregion

    }
    
    /// <summary>
    /// 
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class SectionGroupAttribute : Attribute
    {
        string _sectionGroupName;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sectionGroupName"></param>
        public SectionGroupAttribute(string sectionGroupName)
        {
            _sectionGroupName = sectionGroupName;
        }
        /// <summary>
        /// 
        /// </summary>
        public string SectionGroupName
        {
            get { return _sectionGroupName; }
        }
    }
    /// <summary>
    /// 
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class SectionAttribute : Attribute
    {
        string _sectionName;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sectionName"></param>
        public SectionAttribute(string sectionName)
        {
            _sectionName = sectionName;
        }
        /// <summary>
        /// 
        /// </summary>
        public string SectionName
        {
            get { return _sectionName; }
        }
    }
}
